﻿/*
 * DATAFLOWCORE
 * 
Copyright 2012 - Mindstorm Multitouch Limited

Author - Bertrand Nouvel

DataFlowCore is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

DataFlowCore is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser Public License for more details.
*/

using MongoDB.Bson;
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Linq;



namespace DFlowCore
{
    public partial class Engine : MarshalByRefObject
    {

        [AutoServerCommand("dataflows_list")]
        public IEnumerable<string> DataflowsList()
        {
            return masterDataflows.Select(s => s.name);
        }

        [AutoServerCommand("dataflow_remove_all")]
        public string DataflowRemoveAll()
        {
            if (currentDataflow != null)
            {
                currentDataflow.Dispose();
                currentDataflow = null;
            }
            foreach (DFlow.Dataflow df in masterDataflows)
            {
                df.Dispose();
            }
            masterDataflows.Clear();
            return "ok";
        }

        [AutoServerCommand("dataflow_new")]
        public string DataflowNew(string name = null, bool auto = true)
        {
            DFlow.Dataflow df = new DFlow.Dataflow();
            if (name == null)
            {
                name = System.String.Format("dataflow-{0}", DFlowCore.Time.time);
            }
            df.name = name;
            df.runmode = (auto) ? DFlow.Dataflow.RunMode.Automatic : DFlow.Dataflow.RunMode.Manual;
            masterDataflows.Add(df);
            if (currentDataflow == null)
            {
                currentDataflow = df;
            }
            return "ok";
        }

        [AutoServerCommand("dataflow_delete")]
        public string DataflowDelete(string name)
        {
            if (currentDataflow.name == name)
            {
                currentDataflow = null;
            }
            foreach (DFlow.Dataflow df in masterDataflows.Where(df => df.name == name))
            {
                df.Dispose();
            }
            masterDataflows.RemoveAll(df => df.name == name);
            if ((currentDataflow==null)&&(masterDataflows.Count>0)) {
                currentDataflow = masterDataflows.First();
            }
            return "ok";
        }

        
        /// <summary>
        /// Returns the list of the node in the specified Dataflow
        /// </summary>
        /// <param name="Dataflow_name">An optional master Dataflow name</param>
        /// <returns>list of nodenames</returns>
        [AutoServerCommand("dataflow_list_nodes", "pipeline_list_nodes")]
        public IEnumerable<string> DataflowListNodes(string Dataflow_name = null)
        {
            DFlow.Dataflow p = currentDataflow;
            if (Dataflow_name != null)
            {
                p = masterDataflows.Find(tp => tp.name == Dataflow_name);
            }
            if (p != null)
            {
                return p.GetNodes().Select(n => n.name);
            }
            return new List<string>();
        }




        [AutoServerCommand("dataflow_list_wires", "pipeline_list_wires")]
        public List<BsonDocument> DataflowListWires(string Dataflow_name = null)
        {
            DFlow.Dataflow p = currentDataflow;
            if (Dataflow_name != null)
            {
                p = masterDataflows.Find(tp => tp.name == Dataflow_name);
            }

            System.Collections.Generic.List<BsonDocument> s = new List<BsonDocument>();
            if (p != null)
            {
                foreach (DFlow.Node n in p.GetNodes())
                {
                    foreach (DFlow.Wire w in n.GetOutboundWires())
                    {
                        BsonDocument wd = new BsonDocument();
                        wd.Add("srcnode", w.srcnode.name);
                        wd.Add("srcpin", w.srcpin);
                        wd.Add("dstnode", w.dstnode.name);
                        wd.Add("dstpin", w.dstpin);
                        s.Add(wd);
                    }
                }
            }

            return s;
        }


        [AutoServerCommand("dataflow_list_input_pins", "pipeline_list_input_pins")]
        public List<BsonDocument> DataflowListInputPins(string Dataflow_name=null)
        {
            List<BsonDocument> s = new List<BsonDocument>();
            DFlow.Dataflow p = currentDataflow;
            if (Dataflow_name != null) {
                p = masterDataflows.Find(tp => tp.name == Dataflow_name);
            }

            if (currentDataflow != null) {
                foreach (DFlow.Node n in p.GetNodes())
                {
                    foreach (System.Reflection.FieldInfo fi in n.ListInputPins())
                    {
                        BsonDocument wd = new BsonDocument();
                        wd.Add("nodename", n.name);
                        wd.Add("pinname", fi.Name);
                        wd.Add("type", DFlowCore.BsonUtils.TranslateTypeInfo(fi.FieldType));
                        s.Add(wd);
                    }
                }
            }

            return s;
        }


        [AutoServerCommand("dataflow_reset", "pipeline_reset")]
        public string DataflowReset(string Dataflow_name = null)
        {
            BsonDocument r = new BsonDocument();
            if (currentDataflow == null)
            {
                EngineSetNewDataflow();
            }
            else
            {
                currentDataflow.Reset();
            }
            return "ok";
        }





        /// <summary>
        /// Load
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="Dataflow_name"></param>
        /// <param name="reset"></param>
        /// <returns></returns>
        [AutoServerCommand("dataflow_load_local", "pipeline_load_local")]
        public string DataflowLoadLocal(string filename, string Dataflow_name = null, bool reset = true)
        {
            DFlow.Dataflow p = currentDataflow;
            if (Dataflow_name != null)
            {
                p = masterDataflows.Find(tp => tp.name == Dataflow_name);
            }
            if (p == null) { p = currentDataflow; }
            if (p == null) { EngineSetNewDataflow(); p = currentDataflow; }
            if (reset) { p.Reset(); }
            if (filename.ToLower().EndsWith(".bson"))
            {
                currentDataflow.Load(BsonDocument.ReadFrom(filename), nodetypes);
            }
            else
            {
                currentDataflow.Load(BsonDocument.Parse(System.IO.File.ReadAllText(filename, System.Text.ASCIIEncoding.ASCII)), nodetypes);
            }

            return "ok";
        }






        /// <summary>
        /// save current Dataflow to a specific file
        /// take as parameters :  filename (absolute path on the server)
        /// </summary>
        /// <param name="q"></param>
        /// <returns>"ok" if fine, if an exception occured the exception if forwarded</returns>
        [AutoServerCommand("dataflow_save_local", "pipeline_save_local")]
        public string DataflowSaveLocal(string filename,string Dataflow_name=null)
        {
            DFlow.Dataflow p = currentDataflow;
            if (Dataflow_name != null)
            {
                p = masterDataflows.Find(tp => tp.name == Dataflow_name);
            }
            if (p == null)
            {
                throw new System.Exception("no such Dataflow !");
            }

            if (filename.ToLower().EndsWith(".bson"))
            {
                p.Save().WriteTo(filename);
                return "ok";
            }
            else
            {
                using (System.IO.FileStream fs = System.IO.File.OpenWrite(filename))
                {
                    byte[] b = System.Text.ASCIIEncoding.ASCII.GetBytes(p.Save().ToJson());
                    fs.Write(b, 0, b.Length);
                }
                return "ok";
            }
        }




        [AutoServerCommand("dataflow_list_output_pins", "pipeline_list_output_pins")]
        public System.Collections.Generic.List<BsonDocument> DataflowListOutputPins(string Dataflow_name=null)
        {
            DFlow.Dataflow p = currentDataflow;
            if (Dataflow_name != null)
            {
                p = masterDataflows.Find(tp => tp.name == Dataflow_name);
            }

            System.Collections.Generic.List<BsonDocument> s = new List<BsonDocument>();
            if (p != null)
            {
                foreach (DFlow.Node n in p.GetNodes()) {
                    foreach (System.Reflection.FieldInfo fi in n.ListOutputPins()) {
                        BsonDocument wd = new BsonDocument();
                        wd.Add("nodename", n.name);
                        wd.Add("pinname", fi.Name);
                        wd.Add("type", DFlowCore.BsonUtils.TranslateTypeInfo(fi.FieldType));
                        s.Add(wd);
                    }
                }
            }
            return s;
        }


        [AutoServerCommand("pipeline_process", "dataflow_process")]
        public string DataflowProcess(string Dataflow_name)
        {
            DFlow.Dataflow df = masterDataflows.Find(x => x.name == Dataflow_name);
            if (df.runmode == DFlow.Dataflow.RunMode.Automatic)
            {
                throw new System.ArgumentException();
            }

            df.Process();
            return "ok";
        }


        




    }
}